package cn.xinfei.xdecision.common.service.component.folder.impl;

import cn.xinfei.xdecision.common.dao.component.folder.FolderMapper;
import cn.xinfei.xdecision.common.model.component.folder.Folder;
import cn.xinfei.xdecision.common.model.component.folder.vo.FolderDeleteReqVo;
import cn.xinfei.xdecision.common.model.component.folder.vo.FolderListReqVo;
import cn.xinfei.xdecision.common.model.component.folder.vo.FolderRenameReqVo;
import cn.xinfei.xdecision.common.model.component.folder.vo.FolderSaveReqVo;
import cn.xinfei.xdecision.common.model.datax.enums.EnumUtil;
import cn.xinfei.xdecision.common.model.datax.enums.FolderTypeEnum;
import cn.xinfei.xdecision.common.model.login.SSOUser;
import cn.xinfei.xdecision.common.model.login.SessionManager;
import cn.xinfei.xdecision.common.service.component.decisiontable.DecisionTablesService;
import cn.xinfei.xdecision.common.service.component.decisiontree.DecisionTreeService;
import cn.xinfei.xdecision.common.service.component.folder.FolderService;
import cn.xinfei.xdecision.common.service.component.guiderule.impl.RuleServiceImpl;
import cn.xinfei.xdecision.common.service.component.scorecard.ScorecardService;
import cn.xinfei.xdecision.common.service.datax.datamanage.v2.VariableService;
import cn.xinfei.xdecision.common.utils.enums.enginex.ComponentTypeEnum;
import cn.xinfei.xdecision.common.utils.exception.ApiException;
import cn.xinfei.xdecision.common.utils.exception.enums.ErrorCodeEnum;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.List;

import static cn.xinfei.xdecision.common.utils.exception.enums.ErrorCodeEnum.*;
import static cn.xinfei.xdecision.common.utils.exception.util.ApiExceptionUtil.exception;

@Service
@Slf4j
public class FolderServiceImpl implements FolderService {

    @Autowired
    private FolderMapper folderMapper;

    @Autowired
    private RuleServiceImpl ruleService;

    @Autowired
    private ScorecardService scorecardService;

    @Autowired
    private DecisionTablesService decisionTablesService;

    @Autowired
    private DecisionTreeService decisionTreeService;

    @Autowired
    private VariableService variableService;

    private QueryWrapper<Folder> queryWrapper(String componentType, String folderName, List<Long> orgIdList) {
        QueryWrapper<Folder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("component_type", componentType);
        queryWrapper.eq("name", folderName);
        queryWrapper.in("organ_id", orgIdList);
        return queryWrapper;
    }

    @Override
    public List<Folder> getTreeList(FolderListReqVo folderListReqVo) {

        if (folderListReqVo.getParentId() == null) {
            folderListReqVo.setParentId(0L);
        }

        LambdaQueryWrapper<Folder> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Folder::getParentId, folderListReqVo.getParentId());
        //部门权限
        SSOUser loginAccount = SessionManager.getLoginAccount();
        wrapper.in(Folder::getOrganId, loginAccount.getOrgIdList());

        Integer folderType = folderListReqVo.getFolderType();
        FolderTypeEnum folderTypeEnum = EnumUtil.fromCodeOrThrow(FolderTypeEnum.class, String.valueOf(folderType));

        switch (folderTypeEnum) {
            case VAR:
                wrapper.eq(Folder::getVariableType, folderListReqVo.getVariableType());
                break;
            case COMMPONENT:
                wrapper.eq(Folder::getComponentType, folderListReqVo.getComponentType());
                break;
            default:
                break;
        }

        List<Folder> firstFolders = folderMapper.selectList(wrapper);

        for (Folder folder : firstFolders) {
            switch (folderTypeEnum) {
                case VAR:
                    folder.setChildren(getChildren(folder.getVariableType(), folder.getId(), folderTypeEnum));
                    break;
                case COMMPONENT:
                    folder.setChildren(getChildren(folder.getComponentType(), folder.getId(), folderTypeEnum));
                    break;
                default:
                    break;
            }
        }

        return firstFolders;
    }

    private List<Folder> getChildren(String type, Long parentId, FolderTypeEnum folderTypeEnum) {

        QueryWrapper<Folder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", parentId);

        switch (folderTypeEnum) {
            case VAR:
                queryWrapper.eq("variable_type", type);
                break;
            case COMMPONENT:
                queryWrapper.eq("component_type", type);
                break;
            default:
                break;
        }
        List<Folder> folders = folderMapper.selectList(queryWrapper);
        for (Folder folder : folders) {
            switch (folderTypeEnum) {
                case VAR:
                    folder.setChildren(getChildren(folder.getVariableType(), folder.getId(), folderTypeEnum));
                    break;
                case COMMPONENT:
                    folder.setChildren(getChildren(folder.getComponentType(), folder.getId(), folderTypeEnum));
                    break;
                default:
                    break;
            }
        }
        return folders;
    }


    @Override
    public boolean addFolder(FolderSaveReqVo folderSaveReqVo) {
        SSOUser loginAccount = SessionManager.getLoginAccount();
        Folder existsFolder = folderMapper.selectOne(queryWrapper(folderSaveReqVo.getComponentType(), folderSaveReqVo.getName(), loginAccount.getOrgIdList()));
        if (existsFolder != null) {
            throw exception(FOLDER_NAME_EXISTS);
        }
        Folder folder = new Folder();
        folder.setOrganId(loginAccount.getOrganId());
        BeanUtils.copyProperties(folderSaveReqVo, folder);
        folderMapper.insert(folder);
        return true;
    }

    @Override
    public boolean renameFolder(FolderRenameReqVo folderRenameReqVo) {
        Folder folder = folderMapper.selectById(folderRenameReqVo.getId());
        if (folder == null || !SessionManager.getLoginAccount().getOrgIdList().contains(folder.getOrganId())) {
            throw exception(PARAM_CHECK_ERROR, "文件夹不存在:" + folderRenameReqVo.getName());
        }
        Folder updateEntity = new Folder();
        updateEntity.setId(folderRenameReqVo.getId());
        updateEntity.setName(folderRenameReqVo.getName());
        folderMapper.updateById(updateEntity);
        return true;
    }

    @Override
    public boolean deleteFolder(FolderDeleteReqVo folderDeleteReqVo) {
        SSOUser loginAccount = SessionManager.getLoginAccount();
        Folder folder = folderMapper.selectById(folderDeleteReqVo.getId());
        if (folder == null || !loginAccount.getOrgIdList().contains(folder.getOrganId())) {
            throw exception(PARAM_CHECK_ERROR, "文件夹不存在:" + folderDeleteReqVo.getName());
        }
        boolean isDeleted = false;
        Integer folderType = folderDeleteReqVo.getFolderType();
        FolderTypeEnum folderTypeEnum = EnumUtil.fromCodeOrThrow(FolderTypeEnum.class, String.valueOf(folderType));
        if (FolderTypeEnum.COMMPONENT.equals(folderTypeEnum)) {
            isDeleted = deleteComponentEmptyFolders(folderDeleteReqVo.getComponentType(), folderDeleteReqVo.getId());
        } else if (FolderTypeEnum.VAR.equals(folderTypeEnum)) {
            isDeleted = deleteVarEmptyFolders(folderDeleteReqVo.getVariableType(), folderDeleteReqVo.getId());
        }

        if (!isDeleted) {
            throw exception(FOLDER_DELETE_FAIL);
        }
        return true;
    }

    /**
     * 递归删除空文件夹，子文件夹不为空则删除失败
     *
     * @param variableType 变量类型
     * @param folderId     文件夹id
     * @return boolean
     */
    private boolean deleteVarEmptyFolders(String variableType, Long folderId) {
        boolean allSubFoldersDeleted = true;
        List<Folder> folders = listVarChildrenFolders(variableType, folderId);
        log.info("预计删除文件夹id:{},子文件夹id:{}", folderId, JSONObject.toJSONString(folders));
        if (folders != null && folders.size() > 0) {
            for (Folder folder : folders) {
                if (!deleteVarEmptyFolders(variableType, folder.getId())) {
                    allSubFoldersDeleted = false;
                }
            }
        }
        if (allSubFoldersDeleted && CollectionUtils.isEmpty(listVarCodes(folderId))) {
            folderMapper.deleteById(folderId);
            log.info("删除文件夹:{}成功", folderId);
            return true;
        } else {
            log.info("删除文件夹:{}失败", folderId);
            return false;
        }
    }

    private List<Folder> listVarChildrenFolders(String variableType, Long folderId) {
        QueryWrapper<Folder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("variable_type", variableType);
        queryWrapper.eq("parent_id", folderId);

        return folderMapper.selectList(queryWrapper);
    }

    private List<String> listVarCodes(Long folderId) {
        return variableService.queryByFolderId(folderId);
    }

    /**
     * 递归删除组件中心文件夹
     *
     * @param componentType 组件类型
     * @param folderId      文件夹id
     * @return boolean
     */
    private boolean deleteComponentEmptyFolders(String componentType, Long folderId) {
        boolean allSubFoldersDeleted = true;
        List<Folder> folders = listComponentChildrenFolders(componentType, folderId);
        log.info("预计删除文件夹id:{},子文件夹id:{}", folderId, JSONObject.toJSONString(folders));
        if (folders != null && folders.size() > 0) {
            for (Folder folder : folders) {
                if (!deleteComponentEmptyFolders(componentType, folder.getId())) {
                    allSubFoldersDeleted = false;
                }
            }
        }
        if (allSubFoldersDeleted && CollectionUtils.isEmpty(listComponentIds(componentType, folderId))) {
            folderMapper.deleteById(folderId);
            log.info("删除文件夹:{}成功", folderId);
            return true;
        } else {
            log.info("删除文件夹:{}失败", folderId);
            return false;
        }
    }

    private List<Folder> listComponentChildrenFolders(String componentType, Long folderId) {
        QueryWrapper<Folder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("component_type", componentType);
        queryWrapper.eq("parent_id", folderId);

        return folderMapper.selectList(queryWrapper);
    }

    private List<Long> listComponentIds(String componentType, Long folderId) {
        ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.adapad(componentType);
        if (componentTypeEnum == null) {
            throw new ApiException(ErrorCodeEnum.PARAMS_EXCEPTION.getCode(), ErrorCodeEnum.PARAMS_EXCEPTION.getMessage());
        }

        switch (componentTypeEnum) {
            case COMPLEX_RULE_BASE:
            case SCRIPT_RULE_BASE:
                return ruleService.queryByFolderId(folderId);
            case SCORECARD:
                return scorecardService.queryByFolderId(folderId);
            case DECISION_TREE:
                return decisionTreeService.queryByFolderId(folderId);
            case DECISION_TABLES:
                return decisionTablesService.queryByFolderId(folderId);
            default:
                break;
        }
        return null;
    }

}
